package com.ndood.admin.controller.user;

import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.ServletWebRequest;

import com.ndood.admin.core.constaints.AdminErrCode;
import com.ndood.admin.core.exception.AdminException;
import com.ndood.admin.core.properties.AdminProperties;
import com.ndood.admin.core.web.tools.EmailUtils;
import com.ndood.admin.pojo.comm.vo.AdminResultVo;
import com.ndood.admin.pojo.system.dto.UserDto;
import com.ndood.admin.service.user.AccountInfoService;
import com.ndood.core.utils.AesEncryptUtil;
import com.ndood.core.utils.RegexUtils;
import com.ndood.core.validate.code.ValidateCodeException;
import com.ndood.core.validate.code.ValidateCodeProcessorHolder;
import com.ndood.core.validate.code.ValidateCodeType;

import cn.hutool.core.codec.Base64;
import lombok.extern.slf4j.Slf4j;

/**
 * 忘记密码处理
 */
@Controller
@Slf4j
public class UserForgetPasswordController {
	
	@Autowired
	private AdminProperties adminProperties;

	@Autowired
	private EmailUtils emailUtils;
	
	@Autowired
	private AccountInfoService accountInfoService;
	
	/**
	 * 系统中的校验码处理器
	 */
	@Autowired
	private ValidateCodeProcessorHolder validateCodeProcessorHolder;
	
	/**
	 * 跳转到忘记密码页面
	 */
	@GetMapping("/user/to_forget_pwd")
	public String toForgetPwdPage() {
		return "user/admin-forgetPwd";
	}
	
	/**
	 * 重置密码前的账户校验
	 */
	@PostMapping("/user/forget/forget_change_pwd")
	@ResponseBody
	public AdminResultVo forgetChangePwd(String type, String username, String imageCode, 
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		log.debug("Step1: 验证手机或者邮箱是否合法");
		if(StringUtils.isBlank(type)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"type为空！");
		}
		if(!type.equals("mobile")&&!type.equals("email")) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"无效的类型！");
		}
		if(StringUtils.isBlank(username)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"username为空！");
		}
		if(StringUtils.isBlank(imageCode)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"imageCode为空！");
		}
		if(type.equals("mobile")&&!RegexUtils.checkMobile(username)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"手机号格式错误！");
		}
		if(type.equals("email")&&!RegexUtils.checkEmail(username)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"邮箱格式错误！");
		}
		
		log.debug("Step2: 验证图片验证码");
		try {
			validateCodeProcessorHolder.findValidateCodeProcessor(ValidateCodeType.IMAGE)
					.validate(new ServletWebRequest(request, response));
		} catch (ValidateCodeException exception) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"图片验证码无效！");
		}
		
		log.debug("Step3: 校验邮箱");
		if(RegexUtils.checkEmail(username)){
			UserDto accountInfo = accountInfoService.getAccountSimpleInfoByEmail(username);
			if(accountInfo==null) {
				throw new AdminException(AdminErrCode.ERR_OTHER,"邮箱对应的用户不存在！");
			}
			String userId = accountInfo.getUserId();
			
			log.debug("Step4: 发送重设密码邮件");
			String email = username;
			String aesKey = adminProperties.getEmail().getEncryptKey();
			String from = adminProperties.getEmail().getFrom();
			String domain = adminProperties.getDomain();
			String changePwdUrl = adminProperties.getEmail().getChagnePwdUrl();
			String active = AesEncryptUtil.encrypt(userId + "_" + domain + "_" + from, aesKey);
			String linkid = URLEncoder.encode(Base64.encode(userId, "UTF-8"), "UTF-8");
			emailUtils.sendChangePwdEmail(email, from, "payboyPlus重设密码邮件", email, domain, changePwdUrl, active, linkid);
			
		}else {
			UserDto accountInfo = accountInfoService.getAccountSimpleInfoByMobile(username);
			if(accountInfo==null) {
				throw new AdminException(AdminErrCode.ERR_OTHER,"手机对应的用户不存在！");
			}
		}
		return AdminResultVo.ok().setMsg("验证通过！");
	}
	
	/**
	 * 通过手机修改密码
	 */
	@PostMapping("/user/forget/mobile_change_pwd")
	@ResponseBody
	public AdminResultVo mobileChangePassword(String mobile, String password, String smsCode,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		log.debug("Step1: 校验请求参数");
		if(StringUtils.isBlank(mobile)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"mobile为空！");
		}
		if(StringUtils.isBlank(password)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"password为空！");
		}
		if(StringUtils.isBlank(smsCode)) {
			throw new AdminException(AdminErrCode.ERR_PARAM,"smsCode为空！");
		}
		
		log.debug("Step2: 校验短信或是否属于当前用户");
		UserDto accountInfo = accountInfoService.getAccountSimpleInfoByMobile(mobile);
		if(accountInfo==null) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"该手机对应的用户不存在！");
		}
		
		log.debug("Step3: 校验短信验证码");
		try {
			validateCodeProcessorHolder.findValidateCodeProcessor(ValidateCodeType.SMS)
					.validate(new ServletWebRequest(request, response));
		} catch (ValidateCodeException exception) {
			throw new AdminException(AdminErrCode.ERR_OTHER,"短信验证码无效！");
		}
		
		log.debug("Step4: 修改密码");
		String userId = accountInfo.getUserId();
		accountInfoService.changePassword(userId,password);
		return AdminResultVo.ok().setMsg("重置密码成功！");
	}
	
	/**
	 * 通过邮箱修改密码
	 */
	@GetMapping("/user/forget/to_email_change_pwd")
	public String toEmailChangePassword(String active, String linkid, Model model) {
		
		try {
			log.debug("Step1: 校验请求参数");
			if (StringUtils.isBlank(active)) {
				throw new AdminException(AdminErrCode.ERR_PARAM, "active不能为空！");
			}
			if (StringUtils.isBlank(linkid)) {
				throw new AdminException(AdminErrCode.ERR_PARAM, "linkid不能为空！");
			}
			String userId = URLDecoder.decode(new String(Base64.decode(linkid, "UTF-8")), "UTF-8");

			log.debug("Step2: 验签");
			UserDto accountInfo = accountInfoService.getAccountSimpleInfoById(userId);
			if (accountInfo == null) {
				throw new AdminException(AdminErrCode.ERR_OTHER, "重置密码失败，邮箱不存在对应的用户不存在！");
			}
			String aesKey = adminProperties.getEmail().getEncryptKey();
			String from = adminProperties.getEmail().getFrom();
			String domain = adminProperties.getDomain();

			String localActive = AesEncryptUtil
					.encrypt(accountInfo.getId() + "_" + domain + "_" + from, aesKey);
			if (!localActive.equals(active)) {
				throw new AdminException(AdminErrCode.ERR_OTHER, "重置密码失败，验签失败！");
			}
			
			if(accountInfo.getEmailStatus()==0) {
				throw new AdminException(AdminErrCode.ERR_OTHER, "重置密码失败，该邮箱还未激活！");
			}
			
			log.debug("Step3: 跳转到修改密码页面");
			String email = accountInfo.getEmail();
			String uuid = AesEncryptUtil.encrypt(userId+","+email, aesKey);
			model.addAttribute("uuid", uuid);
			model.addAttribute("email", email);
			return "user/admin-changePwd";

		} catch (Exception e) {
			return "redirect:/user/forget/to_failed?type=email&errMsg=" + e.getMessage();
		}
		
	}
	
	/**
	 * 通过邮箱修改密码
	 */
	@PostMapping("/user/forget/email_change_pwd")
	@ResponseBody
	public AdminResultVo emailChangePassword(String uuid, String email, String password, String repassword) throws Exception {
		
		log.debug("Step1: 校验请求参数");
		if (StringUtils.isBlank(uuid)) {
			throw new AdminException(AdminErrCode.ERR_PARAM, "uuid不能为空！");
		}
		if (StringUtils.isBlank(email)) {
			throw new AdminException(AdminErrCode.ERR_PARAM, "email不能为空！");
		}
		if (StringUtils.isBlank(password)) {
			throw new AdminException(AdminErrCode.ERR_PARAM, "password不能为空！");
		}
		if (!password.equals(repassword)) {
			throw new AdminException(AdminErrCode.ERR_PARAM, "两次输入的密码不一致！");
		}
		
		log.debug("Step2: 验证签名");
		String aesKey = adminProperties.getEmail().getEncryptKey();
		String rawStr = AesEncryptUtil.decrypt(uuid, aesKey);
		if(rawStr.indexOf(",") < 0) {
			throw new AdminException(AdminErrCode.ERR_PARAM, "非法的uuid！");
		}
		String userId = rawStr.trim().split(",")[0];
		String email2 = rawStr.trim().split(",")[1];
		if(!email.equals(email2)) {
			throw new AdminException(AdminErrCode.ERR_PARAM, "非法的email！");
		}
		
		log.debug("Step3: 更新用户密码");
		UserDto accountInfo = accountInfoService.getAccountSimpleInfoById(userId);
		if(accountInfo==null) {
			throw new AdminException(AdminErrCode.ERR_PARAM, "非法的uuid！");
		}
		if(!email.equals(accountInfo.getEmail())) {
			throw new AdminException(AdminErrCode.ERR_PARAM, "非法的email！");
		}
		accountInfoService.changePassword(userId, password);
		
		return AdminResultVo.ok().setMsg("重置密码成功！");
	}
	
	/**
	 * 重置密码成功跳转
	 */
	@GetMapping("/user/forget/to_success")
	public String signUpSuccess(String type, String username, Model model) throws Exception {
		model.addAttribute("type", type);
		if ("email".equals(type)) {
			model.addAttribute("email", username);
		} else if ("mobile".equals(type)) {
			model.addAttribute("mobile", username);
		} else {
			String msg = "无效的类型！";
			return "redirect:/user/forget/to_failed?type=email?errMsg=" + URLEncoder.encode(msg, "utf-8");
		}
		return "user/admin-forgetPwd-success";
	}

	/**
	 * 重置密码失败跳转
	 */
	@GetMapping("/user/forget/to_failed")
	public String signUpFailed(String type, String errMsg, Model model) throws AdminException {
		model.addAttribute("type", type);
		if ("email".equals(type)) {
			model.addAttribute("errMsg", errMsg);
		} else if ("mobile".equals(type)) {
			model.addAttribute("errMsg", errMsg);
		} else {
			throw new AdminException(AdminErrCode.ERR_PARAM,errMsg);
		}
		return "user/admin-forgetPwd-failed";
	}
	
}
